package com.wanger.swc.util.http;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.wanger.swc.util.http.model.HttpReqInfo;
import com.wanger.swc.util.http.model.ReturnType;
import com.wanger.swc.util.validation.MyVerifyUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Component
public class MyHttpUtil<T> {

    @Resource
    private RestTemplate restTemplate;

    /**
     * 获取带有参数的url
     *
     * @param info 请求信息
     * @return 返回带有参数的url
     */
    private static String getUrl(HttpReqInfo info) {
        String url = info.getUrl();
        Map<String, String> params = info.getParams();

        // 如果URL为空，返回空字符串
        if (StrUtil.isBlank(url)) return "";

        // 如果参数为空，直接返回URL
        if (CollUtil.isEmpty(params)) return url;

        // 1. 如果url已经带有部分参数了，则把params的参数追加上去
        if (url.contains("?")) {
            // URL中已含有参数，直接拼接参数
            url = url + "&" + getParamString(params);
        } else {
            // 2. 如果url没有携带任何参数，则使用？隔开把params的参数追加上去
            url = url + "?" + getParamString(params);
        }
        return Boolean.TRUE.equals(info.getEncode()) ?
                HttpUtil.encodeParams(url, Charset.defaultCharset()) : url;
    }

    /**
     * 将参数Map转化为URL参数的格式
     *
     * @param params 参数集合
     * @return 拼接好的参数
     */
    private static String getParamString(Map<String, String> params) {
        //参数为空直接返回空字符串
        if (CollUtil.isEmpty(params)) return "";
        //不为空则映射为指定格式
        return params.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
    }

    /**
     * 代理请求
     *
     * @param info 请求信息
     * @return 请求返回的数据
     */
    public ResponseEntity<?> proxyRequest(HttpReqInfo info) {
        MyVerifyUtil.nullVerify(info, "请求信息不能为空！");
        MyVerifyUtil.nullVerify(info::getUrl, "请求url不能为空！");
        MyVerifyUtil.nullVerify(info::getMethod, "请求方式不能为空！");
        // 拼接完整的目标 URL
        if (StrUtil.isBlank(info.getReturnType())) {
            info.setReturnType(ReturnType.returnString.name());
        }

        String targetUrl = getUrl(info);

        // 获取前端请求的方法类型
        HttpMethod httpMethod = HttpMethod.valueOf(info.getMethod().toUpperCase());

        // 构建请求头，传递前端请求的头部
        HttpHeaders headers = new HttpHeaders();

        // 通过 Enumeration 迭代请求头
        if (CollUtil.isNotEmpty(info.getHeaders())) info.getHeaders().forEach(headers::add);

        // 创建请求实体，包括请求头和请求体
        HttpEntity<String> entity = StrUtil.isBlank(info.getBody()) ? new HttpEntity<>(headers) : new HttpEntity<>(info.getBody(), headers);

        // 发起请求并返回结果
        ResponseEntity<?> response = restTemplate.exchange(targetUrl, httpMethod, entity, ReturnType.valueOf(info.getReturnType()).getTypeClass());
        log.info("请求【{}】成功！", targetUrl);
        // 返回响应结果
        return ResponseEntity.status(response.getStatusCode())
                .headers(response.getHeaders())
                .body(response.getBody());
    }

    /**
     * 请求代理
     *
     * @param url          目标url
     * @param request      原始请求体
     * @param body         body数据
     * @param queryParams  请求参数
     * @param responseType 响应类型
     * @return 返回响应数据
     */
    public ResponseEntity<T> proxyRequest(String url, HttpServletRequest request, String body, Map<String, String> queryParams, Class<T> responseType) {
        HttpReqInfo info = new HttpReqInfo();
        info.setUrl(url);
        info.setParams(queryParams);
        info.setBody(body);
        info.setMethod(request.getMethod().toUpperCase());
        info.setReturnType(ReturnType.getReturnType(responseType));

        Enumeration<String> headerNames = request.getHeaderNames();
        Map<String, String> handrs = new HashMap<>();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            handrs.put(headerName, request.getHeader(headerName));
        }
        info.setHeaders(handrs);

        @SuppressWarnings("all")
        ResponseEntity<T> entity = (ResponseEntity<T>) this.proxyRequest(info);
        return entity;
    }

}
